from datetime import date, datetime, timedelta
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, func

from backend.config.database import get_db
from backend.entities.prediction import PredResult
from backend.entities.load_data_new import LoadData
from backend.schemas.responses import SingleDayPredictionResponse, MultiDayPredictionResponse, MultiDayPredictionData, SingleDayPredictionData

router = APIRouter(prefix="/prediction", tags=["预测分析"])


@router.get("/seven-days", response_model=MultiDayPredictionResponse)
async def get_seven_days_prediction(
    start_day: int = Query(1, ge=1, le=7, description="开始天数(1-7,1为当天)"),
    end_day: int = Query(7, ge=1, le=7, description="结束天数(1-7)"), 
    models: Optional[str] = Query(None, description="模型筛选,逗号分隔,如'lstm,rf'"),
    db: Session = Depends(get_db)
):
    """
    获取七天预测数据的任意区间
    - start_day: 开始天数(1=今天,2=明天...)
    - end_day: 结束天数
    - models: 可选的模型筛选
    """
    if start_day > end_day:
        raise HTTPException(status_code=400, detail="开始天数不能大于结束天数")
    
    # 计算日期范围
    today = date.today()
    start_date = today + timedelta(days=start_day-1)
    end_date = today + timedelta(days=end_day-1)
    
    # 构建查询条件
    query = db.query(PredResult).filter(
        and_(
            PredResult.dt >= start_date,
            PredResult.dt <= end_date
        )
    )
    
    # 模型筛选
    if models:
        model_list = [m.strip() for m in models.split(',')]
        query = query.filter(PredResult.model.in_(model_list))
    
    # 按日期和时间点排序
    predictions = query.order_by(PredResult.dt, PredResult.t_idx).all()
    
    if not predictions:
        raise HTTPException(status_code=404, detail="未找到指定范围的预测数据")
    
    return MultiDayPredictionResponse.create(
        data=MultiDayPredictionData(
            start_date=start_date.isoformat(),
            end_date=end_date.isoformat(),
            day_count=end_day - start_day + 1,
            predictions=[{"dt": p.dt, "t_idx": p.t_idx, "pred_val": p.pred_val, "model": p.model} for p in predictions],
            models_included=list(set([str(p.model) for p in predictions]))
        ),
        message="获取多日预测数据成功"
    )


@router.get("/single-day/{target_date}", response_model=SingleDayPredictionResponse)
async def get_single_day_prediction(
    target_date: date,
    models: Optional[str] = Query(None, description="模型筛选"),
    db: Session = Depends(get_db)
):
    """获取指定日期的预测数据"""
    query = db.query(PredResult).filter(PredResult.dt == target_date)
    
    if models:
        model_list = [m.strip() for m in models.split(',')]
        query = query.filter(PredResult.model.in_(model_list))
    
    predictions = query.order_by(PredResult.t_idx).all()
    
    if not predictions:
        raise HTTPException(status_code=404, detail=f"未找到{target_date}的预测数据")
    
    return SingleDayPredictionResponse.create(
        data=SingleDayPredictionData(
            date=target_date.isoformat(),
            predictions=[{"dt": p.dt, "t_idx": p.t_idx, "pred_val": p.pred_val, "model": p.model} for p in predictions]
        ),
        message="获取单日预测数据成功"
    )


@router.get("/comparison/{target_date}")
async def get_prediction_vs_actual(
    target_date: date,
    model: str = Query(..., description="模型名称"),
    db: Session = Depends(get_db)
):
    """预测值与实际值对比分析"""
    # 获取预测值
    pred_data = db.query(PredResult).filter(
        and_(
            PredResult.dt == target_date,
            PredResult.model == model
        )
    ).order_by(PredResult.t_idx).all()
    
    # 获取实际值
    actual_data = db.query(LoadData).filter(
        LoadData.dt == target_date
    ).order_by(LoadData.t_idx).all()
    
    if not pred_data:
        raise HTTPException(status_code=404, detail="未找到预测数据")
    
    if not actual_data:
        # 如果没有实际值，返回仅预测数据
        return {
            "date": target_date,
            "model": model,
            "has_actual": False,
            "predictions": [{"time_idx": p.t_idx, "pred_value": p.pred_val} for p in pred_data]
        }
    
    # 组合预测值和实际值
    comparison_data = []
    actual_dict = {a.t_idx: a.load_val for a in actual_data}
    
    for pred in pred_data:
        actual_val = actual_dict.get(pred.t_idx)
        error = None
        if actual_val is not None:
            pred_val = float(pred.pred_val) if pred.pred_val is not None else 0.0  # type: ignore
            act_val = float(actual_val) if actual_val is not None else 0.0  # type: ignore
            error = abs(pred_val - act_val)
        
        comparison_data.append({
            "time_idx": pred.t_idx,
            "datetime": pred.dtm,
            "pred_value": pred.pred_val,
            "actual_value": actual_val,
            "error": error
        })
    
    return {
        "date": target_date,
        "model": model,
        "has_actual": True,
        "comparison": comparison_data,
        "summary": {
            "mae": sum([d["error"] for d in comparison_data if d["error"] is not None]) / len([d for d in comparison_data if d["error"] is not None]) if any(d["error"] is not None for d in comparison_data) else None
        }
    }


@router.get("/models")
async def get_available_models(db: Session = Depends(get_db)):
    """获取可用的预测模型列表"""
    models = db.query(PredResult.model).distinct().all()
    return {"models": [m[0] for m in models]}


@router.get("/date-range")
async def get_prediction_date_range(db: Session = Depends(get_db)):
    """获取预测数据的日期范围"""
    result = db.query(
        func.min(PredResult.dt).label('min_date'),
        func.max(PredResult.dt).label('max_date')
    ).first()
    
    if result is None or result.min_date is None or result.max_date is None:
        return {
            "min_date": None,
            "max_date": None,
            "total_days": 0
        }
    else:
        return {
            "min_date": result.min_date,
            "max_date": result.max_date,
            "total_days": (result.max_date - result.min_date).days + 1
        }